/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package moodlerest;

import java.io.*;
import java.net.*;
import java.net.URL;
import java.util.logging.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Contains static routines to initialise the REST web service for authentication and to call the Moodle web service.
 * @author Bill Antonia
 */
public class MoodleRestWebService {

    private static String token = null;
    private static String username = null;
    private static String password = null;
    private static String url = null;

    /**
     * Constructor which currently does nothing.
     */
    public MoodleRestWebService() {
    }

    /**
     * One init method MUST be called before any other call to any other MoodleRestXXXXXXX Classes to initialise the Moodle URL web server service and authentication.
     * url contains the URL of the REST server service within the Moodle site.
     * token Contains the token provided by the Moodle installation for access to the configured REST web services.
     * @param url String
     * @param token String
     */
    public static void init(String url, String token) {
        MoodleRestWebService.token = token;
        MoodleRestWebService.url = url;
    }

    /**
     * One init method MUST be called before any other call to any other MoodleRestXXXXXXX Classes to initialise the Moodle URL web server service and authentication.
     * url contains the URL of the REST server service within the Moodle site.
     * username password pair Contains the username and password for authentication to the Moodle configured REST web services.
     * @param url String
     * @param username String
     * @param password String
     */
    public static void init(String url, String username, String password) {
        MoodleRestWebService.username = username;
        MoodleRestWebService.password = password;
        MoodleRestWebService.url = url;
    }

    /**
     * Returns the currently configured token or null if not set.
     * @return token String
     */
    public static String getToken() {
        return token;
    }

    /**
     * Returns the currently configured username or null if not set.
     * @return username String
     */
    public static String getUsername() {
        return username;
    }

    /**
     * Returns the currently configured password or null if not set.
     * @return password String
     */
    public static String getPassword() {
        return password;
    }

    /**
     * Returns the currently configured URL or null if not set.
     * @return url String
     */
    public static String getURL() {
        return url;
    }

    /**
     * Sets the authentication token.
     * @param token String
     */
    public static void setAuth(String token) {
        MoodleRestWebService.token = token;
    }

    /**
     * Sets the username/password pair for authentication.
     * @param username String
     * @param password String
     */
    public static void setAuth(String username, String password) {
        MoodleRestWebService.username = username;
        MoodleRestWebService.password = password;
    }

    /**
     * Returns the HTTP encoded string required for web service authentication. Order of authentication methods: token then username/password, if token not initialised or null if both methods not initialised.
     * @return String containing HTTP encoded string or null.
     * @throws UnsupportedEncodingException
     */
    public static String getAuth() throws UnsupportedEncodingException {
        StringBuilder data = new StringBuilder();
        if (MoodleRestWebService.getToken() != null) {
            data.append(URLEncoder.encode("wstoken", "UTF-8")).append("=").append(URLEncoder.encode(MoodleRestWebService.getToken(), "UTF-8"));
        } else {
            if (MoodleRestWebService.getUsername() != null && MoodleRestWebService.getPassword() != null) {
                data.append(URLEncoder.encode("wsusername", "UTF-8")).append("=").append(URLEncoder.encode(MoodleRestWebService.getUsername(), "UTF-8"));
                data.append("&"); // Fix by César Martínez
                data.append(URLEncoder.encode("wspassword", "UTF-8")).append("=").append(URLEncoder.encode(MoodleRestWebService.getPassword(), "UTF-8"));
            } else {
                return null;
            }
        }
        return data.toString();
    }

    /**
     * Sets the URL to the REST server service within the Moodle site.
     * @param url String
     */
    public static void setURL(String url) {
        MoodleRestWebService.url = url;
    }

    /**
     * This calls the external Moodle web service.
     * params String containing the parameters of the call.
     * elements NodeList containing name/value pairs of returned XML data.
     * @param params String
     * @return elements NodeList
     */
    public static Document call(String params) {
        Document document = null;
        try {
            URL getUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept", "application/xml");
            connection.setDoOutput(true);
            OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
            writer.write(params);
            writer.flush();
            writer.close();
            // Used for testing
            /*BufferedReader reader=new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line=reader.readLine();
            while (line!=null) {
            System.out.println(line);
            line=reader.readLine();
            }
            reader.close();*/

            // Passar o InputStream para String (adicionando resolução de entidades)
            String text = Util.convertStreamToString(connection.getInputStream());
            //System.out.println(text);
            // Criar elemento do tipo Document
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            // Validar o XML, convertendo de String para InputStream (agora já com as entidades resolvidas).
            document = db.parse(new ByteArrayInputStream(text.getBytes("UTF-8")));

            // Used for testing
            /*for (int j = 0; j < elements.getLength(); j++) {
            String content = elements.item(j).getTextContent();
            String nodeName = elements.item(j).getParentNode().getAttributes().getNamedItem("name").getNodeValue();
            System.out.println(nodeName + "=" + content);
            }*/
            connection.disconnect();
        } catch (SAXException ex) {
            Logger.getLogger(MoodleRestWebService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(MoodleRestWebService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(MoodleRestWebService.class.getName()).log(Level.SEVERE, null, ex);
        }
        return document;
    }
}
